/*==============================================================*/
/* program: freetree.c                                          */
/* purpose: generating all free trees                           */
/* input  : n -- number of nodes                                */
/*          m -- max degree                                     */
/*          lb,ub -- lower and upper bound on diameter          */
/* output : listing of free trees in relex order                */
/* date   : September 1995, updated Sept 2000                   */
/* programmers: Gang Li & Frank Ruskey                          */
/* algorithm: From the paper: G. Li and F. Ruskey,  "The        */
/*    Advantages of Forward Thinking in Generating Rooted and   */
/*    Free Trees",  10th Annual ACM-SIAM Symposium on Discrete  */
/*    Algorithms (SODA), (1999) S939-940.  See the web page at  */
/*    http://www.theory.csc.UVic.CA/~fruskey/                   */
/*      Publications/RootedFreeTree.html                        */
/* more info: See                                               */
/*    http://www.theory.csc.UVic.CA/inf/FreeTrees.html     */
/*==============================================================*/

#include <stdio.h>
#include <iostream>
using namespace std;

#define MAX_SIZE   50  /* max size of the tree */
#define TRUE        1
#define FALSE       0

int
 par[MAX_SIZE],                 /* parent position of i  */
 L[MAX_SIZE],                   /* level of node i       */
 k,                             /* max number of children */
 chi[MAX_SIZE],                 /* number of children of a node */
 nextp[MAX_SIZE],               /* next good pos to add nodes */
 rChi[MAX_SIZE],                /* the right most child of node i */
 ub;                            /* upper bound           */
unsigned __int64 num;        /* number of trees */

int N;  /* Corresponds to -n */
int K;  /*                -k */
int M;            /*      -m */
int U;            /*      -u */

const unsigned int maxN = 30; // Code added by W. Bomfim
const unsigned int minN = 3;
unsigned __int64 an;        // a(n)
unsigned int Grau[maxN+1], // Grau[i], 1<=i<=N, is the degree of i.
maxL, // Maximum of the array L.
top, P[maxN]; // Stack of original leaves
bool centered; // true iff the tree is centered.

void Centered(unsigned int u){
static unsigned int i, v, L;
for(i=0; i<top; i++){// For each original leaf v
    v = P[i];
    L = 0;
    do {
        v = par[v];
        L++; }
    while ((v != 1)&&(v != u));
    if(v == 1)
        L++;
    if(L > maxL){
        centered = true;
        return;
        }
    }
centered = false;
}

unsigned int Wiener_index(){
static unsigned int W, u, v, i, cGrau[maxN+1],
                    Q[maxN], F, R,
                    Order[maxN+1];
F = R = 0; W = 0;
top = 0;
for(u=1; u<=N; u++){
    Order[u] = 1;
    if(Grau[u]==1){
        Q[R] = u; R++; P[top] = u; top++;}
    else cGrau[u] = Grau[u];
    }
for(i=1; i<N; i++){
    u = Q[F]; F++;
    v = par[u];
    Order[v] = Order[v] + Order[u];
    cGrau[v]--;
    if(cGrau[v]==1){
        Q[R] = v; R++;}
    W += Order[u] * (N-Order[u]);
    }
Centered(u);
return W;
}

void FindGrau_maxL(){
unsigned int u;
Grau[1] = 0;
for(u=2; u<=N; u++)
    Grau[u] = 1;
for(u=1; u<=N; u++)
    Grau[par[u]]++;
maxL = L[1];
for(u=2; u<=N; u++)
    if(L[u] > maxL)
        maxL = L[u];
}

void inicialize(){
an = 0;
FindGrau_maxL();
}

void PrintIt() {
unsigned int I;
num++;
if(num == 1)
    inicialize();
I = Wiener_index();
if(centered)
    an += I;
}// End of code added by W. Bomfim

void updateL() {
    int i;
    L[1]=0;
    maxL = 0;
    for ( i=2; i<=N; ++i ){L[i] = L[par[i]]+1; if(L[i] > maxL) maxL = L[i];}
}

int good( int p, int h, int t ) {
  if (p==2 && K<=2 && t==0) return TRUE;
  if (t == 1) {
     if (2*h>=K+1 && 2*h <= U+1) {
        if ((p-1)*2 >= N) return TRUE;
        else if (p - h-1 == 1) {
          if (par[p]> 2) return TRUE;
        } else
          if ((p - h-1 >=2) && ((par[h+2]>2) || (par[h+3]>2))) return TRUE;
     }
  } else
  if (N-p >= h && 2*h>=K) {
     if (U==N-1 && N%2==0) return(2*h<=U+1);
     else return(2*h <= U);
  }
  return FALSE;
} /* good */

void Gen( int p, int s, int cL, int h, int l, int n, int f, int g ) {
  int hh,flag,entry,temp;       // Added instructions to modify the array Grau. - W. Bomfim
  if (p > n)
     if (f == 0) {
        if (good(p-1,h,0)) Gen(p, 2, p-2,h,n,N,1,0);
        if (good(p-1,h,1)) Gen(p, 2, p-3,h,n,N,1,1);
     } else { updateL(); PrintIt();}
  else {
     if (cL == 0) {
        if ( p< ub+2 ){ Grau[par[p]]--; par[p] = p-1; Grau[p-1]++;}
        else {
           Gen( p, p-1, 1, h, l, n, f, g );
           return;
        }
     } else
        if (par[p-cL] < s){Grau[par[p]]--; par[p]=par[p-cL]; Grau[par[p]]++;}
        else {
           Grau[par[p]]--;
           par[p] = cL + par[p-cL];
            Grau[par[p]]++;
           if (g==1)
               if (((l-1)*2 < n) && (p-cL<=l) && (
                   ((p-cL+1<l) &&  (par[p-cL+1]==2)
                   && (p-cL+2<=l) && (par[p-cL+2]==2))     /*case 1*/
                   || ((p-cL+1==l) && (par[p-cL+1]==2))    /*case 2*/
                   || (p-cL+1>l))) {                       /*case 3*/
                  s= par[p]; cL= p-s;
                  Grau[par[p]]--;
                  par[p] = par[par[p]];
                  Grau[par[p]]++;
               } else
                  if (par[p-cL]==2){Grau[par[p]]--; par[p]=1; Grau[1]++;}
        }
        if (s!=0 || p<=ub+1) {
           chi[par[p]] = chi[par[p]] + 1;
           temp = rChi[par[p]]; rChi[par[p]] = p;
           if (chi[par[p]] <= ((par[p]==1)?k:k-1)) {
              if (chi[par[p]] < (par[p]==1?k:k-1)) nextp[p] = par[p];
              else nextp[p] = nextp[par[p]];
              Gen( p+1, s, cL,h,l,n,f,g );
           }
           chi[par[p]] = chi[par[p]] - 1;
           rChi[par[p]] = temp;
        }
        if (s==0 && 2*(p-2)<K) return;

        nextp[p] = nextp[par[p]];
        entry = nextp[p];
        flag= 0; hh=1;
        while ((((f==0) && (entry>=2)) ||
	       ((f==1) && (entry>=1))) && (flag==0)) {
           if (s==0) h = p-2;
           if (p<=l+h-g) hh = 0;
           if ((f==0) || (hh==1)) {
              /*s = par[p]; par[p] = par[s];*/
              Grau[par[p]]--;
              par[p] = entry;
              Grau[entry]++;
              chi[entry] = chi[entry] + 1;
	      temp = rChi[par[p]];  rChi[par[p]] = p;
	      if (chi[entry] >= (entry==1?k:k-1)) nextp[p] = nextp[entry];
              if (f == 0) Gen(p+1,temp,p-temp,h,0,N-h+1,f,g);
              else if (hh == 1) Gen(p+1,temp,p-temp,h,l,n,f,g);
	      chi[entry] = chi[entry] - 1;
	      rChi[par[p]] = temp;
	      entry = nextp[entry];
	      nextp[p] = entry;
           } else flag= 1;
        }
        if (f == 0) {
           if (good(p-1,h,0)) Gen(p,2,p-2,h,p-1,N,1,0);
           if (good(p-1,h,1)) Gen(p,2,p-3,h,p-1,N,1,1);
        }
  }
} /* Gen */

main() {                // code modified by W. Bomfim
int i;
K = 2;
par[1] = 0; par[2] = 1;
printf("Beggining with a(%d)\n", minN);
for(N = minN; N <= maxN; N++){
    num = 0;
    M = N-1;
    U = N-1;
    ub = (U+1)/2;
    k = M;
    for(i=1;i<=N;i++)
        chi[i]=0;
    nextp[1]=0; nextp[2]=1;chi[1]=1;
    Gen( 3, 0, 0, ub, 0, N-ub+1, 0, 0 );
    cout << an << ", ";
    }
return(0);
}